# -*- coding: utf-8 -*-
# Author   : ZhangQing
# Time     : 2025-08-12 10:30
# File     : error_handlers.py
# Project  : codebuddy_craft
# Desc     : API错误处理

"""
API错误处理 🛡️

提供统一的API错误处理机制，包括异常捕获、日志记录和响应格式化
"""

import logging
import traceback
from typing import Dict, Any, Optional, Callable, Type

from fastapi import FastAPI, Request, status
from fastapi.responses import JSONResponse
from fastapi.exceptions import RequestValidationError
from sqlalchemy.exc import SQLAlchemyError, IntegrityError
from pydantic import ValidationError

from backend.utils.logger import log_error_with_context, get_security_logger

logger = logging.getLogger(__name__)
security_logger = get_security_logger()


class APIError(Exception):
    """API错误基类 🚫"""
    
    def __init__(
        self, 
        message: str, 
        status_code: int = status.HTTP_500_INTERNAL_SERVER_ERROR,
        error_code: str = "internal_error",
        details: Optional[Dict[str, Any]] = None
    ):
        self.message = message
        self.status_code = status_code
        self.error_code = error_code
        self.details = details or {}
        super().__init__(message)


class BadRequestError(APIError):
    """请求错误 🚫"""
    
    def __init__(self, message: str, error_code: str = "bad_request", details: Optional[Dict[str, Any]] = None):
        super().__init__(
            message=message,
            status_code=status.HTTP_400_BAD_REQUEST,
            error_code=error_code,
            details=details
        )


class UnauthorizedError(APIError):
    """未授权错误 🔒"""
    
    def __init__(self, message: str = "未授权访问", error_code: str = "unauthorized", details: Optional[Dict[str, Any]] = None):
        super().__init__(
            message=message,
            status_code=status.HTTP_401_UNAUTHORIZED,
            error_code=error_code,
            details=details
        )


class ForbiddenError(APIError):
    """禁止访问错误 🚫"""
    
    def __init__(self, message: str = "禁止访问", error_code: str = "forbidden", details: Optional[Dict[str, Any]] = None):
        super().__init__(
            message=message,
            status_code=status.HTTP_403_FORBIDDEN,
            error_code=error_code,
            details=details
        )


class NotFoundError(APIError):
    """资源不存在错误 🔍"""
    
    def __init__(self, message: str = "资源不存在", error_code: str = "not_found", details: Optional[Dict[str, Any]] = None):
        super().__init__(
            message=message,
            status_code=status.HTTP_404_NOT_FOUND,
            error_code=error_code,
            details=details
        )


class ConflictError(APIError):
    """资源冲突错误 ⚠️"""
    
    def __init__(self, message: str = "资源冲突", error_code: str = "conflict", details: Optional[Dict[str, Any]] = None):
        super().__init__(
            message=message,
            status_code=status.HTTP_409_CONFLICT,
            error_code=error_code,
            details=details
        )


class RateLimitError(APIError):
    """速率限制错误 ⏱️"""
    
    def __init__(self, message: str = "请求过于频繁", error_code: str = "rate_limit", details: Optional[Dict[str, Any]] = None):
        super().__init__(
            message=message,
            status_code=status.HTTP_429_TOO_MANY_REQUESTS,
            error_code=error_code,
            details=details
        )


class ServerError(APIError):
    """服务器错误 ⚠️"""
    
    def __init__(self, message: str = "服务器内部错误", error_code: str = "server_error", details: Optional[Dict[str, Any]] = None):
        super().__init__(
            message=message,
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            error_code=error_code,
            details=details
        )


class ServiceUnavailableError(APIError):
    """服务不可用错误 🔌"""
    
    def __init__(self, message: str = "服务暂时不可用", error_code: str = "service_unavailable", details: Optional[Dict[str, Any]] = None):
        super().__init__(
            message=message,
            status_code=status.HTTP_503_SERVICE_UNAVAILABLE,
            error_code=error_code,
            details=details
        )


def format_error_response(
    status_code: int,
    message: str,
    error_code: str = "error",
    details: Optional[Dict[str, Any]] = None,
    request_id: Optional[str] = None
) -> Dict[str, Any]:
    """格式化错误响应 📝

    Args:
        status_code: HTTP状态码
        message: 错误消息
        error_code: 错误代码
        details: 错误详情
        request_id: 请求ID

    Returns:
        格式化的错误响应
    """
    response = {
        "success": False,
        "error": {
            "code": error_code,
            "message": message,
            "status": status_code,
        }
    }
    
    if details:
        response["error"]["details"] = details
        
    if request_id:
        response["request_id"] = request_id
        
    return response


def get_request_id(request: Request) -> Optional[str]:
    """获取请求ID 🔍

    Args:
        request: FastAPI请求对象

    Returns:
        请求ID
    """
    return getattr(request.state, "request_id", None)


def get_client_info(request: Request) -> Dict[str, Any]:
    """获取客户端信息 📱

    Args:
        request: FastAPI请求对象

    Returns:
        客户端信息
    """
    return {
        "ip": request.client.host if request.client else "unknown",
        "user_agent": request.headers.get("user-agent", "unknown"),
        "path": request.url.path,
        "method": request.method,
    }


def setup_error_handlers(app: FastAPI) -> None:
    """设置错误处理器 🛡️

    Args:
        app: FastAPI应用实例
    """
    
    @app.exception_handler(APIError)
    async def handle_api_error(request: Request, exc: APIError) -> JSONResponse:
        """处理API错误"""
        request_id = get_request_id(request)
        client_info = get_client_info(request)
        
        # 记录错误日志
        log_level = logging.ERROR if exc.status_code >= 500 else logging.WARNING
        logger.log(
            log_level,
            f"API错误 [{exc.error_code}]: {exc.message}",
            extra={
                "status_code": exc.status_code,
                "error_code": exc.error_code,
                "path": request.url.path,
                "method": request.method,
                "client_ip": client_info["ip"],
                "request_id": request_id,
            }
        )
        
        # 记录安全相关错误
        if isinstance(exc, (UnauthorizedError, ForbiddenError)):
            security_logger.log_suspicious_activity(
                f"访问被拒绝: {exc.message}",
                path=request.url.path,
                method=request.method,
                ip_address=client_info["ip"],
                status_code=exc.status_code
            )
        
        return JSONResponse(
            status_code=exc.status_code,
            content=format_error_response(
                status_code=exc.status_code,
                message=exc.message,
                error_code=exc.error_code,
                details=exc.details,
                request_id=request_id
            )
        )
    
    @app.exception_handler(RequestValidationError)
    async def handle_validation_error(request: Request, exc: RequestValidationError) -> JSONResponse:
        """处理请求验证错误"""
        request_id = get_request_id(request)
        client_info = get_client_info(request)
        
        # 格式化验证错误
        error_details = []
        for error in exc.errors():
            error_details.append({
                "loc": error["loc"],
                "msg": error["msg"],
                "type": error["type"]
            })
        
        logger.warning(
            f"请求验证错误: {request.url.path}",
            extra={
                "status_code": status.HTTP_422_UNPROCESSABLE_ENTITY,
                "error_code": "validation_error",
                "path": request.url.path,
                "method": request.method,
                "client_ip": client_info["ip"],
                "request_id": request_id,
                "errors": error_details
            }
        )
        
        return JSONResponse(
            status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
            content=format_error_response(
                status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
                message="请求数据验证失败",
                error_code="validation_error",
                details={"errors": error_details},
                request_id=request_id
            )
        )
    
    @app.exception_handler(ValidationError)
    async def handle_pydantic_validation_error(request: Request, exc: ValidationError) -> JSONResponse:
        """处理Pydantic验证错误"""
        request_id = get_request_id(request)
        
        # 格式化验证错误
        error_details = []
        for error in exc.errors():
            error_details.append({
                "loc": error["loc"],
                "msg": error["msg"],
                "type": error["type"]
            })
        
        return JSONResponse(
            status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
            content=format_error_response(
                status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
                message="数据验证失败",
                error_code="validation_error",
                details={"errors": error_details},
                request_id=request_id
            )
        )
    
    @app.exception_handler(SQLAlchemyError)
    async def handle_sqlalchemy_error(request: Request, exc: SQLAlchemyError) -> JSONResponse:
        """处理数据库错误"""
        request_id = get_request_id(request)
        client_info = get_client_info(request)
        
        # 记录错误日志
        log_error_with_context(
            exc,
            {
                "path": request.url.path,
                "method": request.method,
                "client_ip": client_info["ip"],
                "request_id": request_id,
            }
        )
        
        # 处理特定类型的数据库错误
        if isinstance(exc, IntegrityError):
            # 完整性错误（如唯一约束违反）
            return JSONResponse(
                status_code=status.HTTP_409_CONFLICT,
                content=format_error_response(
                    status_code=status.HTTP_409_CONFLICT,
                    message="数据冲突，可能是重复记录",
                    error_code="data_conflict",
                    request_id=request_id
                )
            )
        
        # 其他数据库错误
        return JSONResponse(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            content=format_error_response(
                status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
                message="数据库操作失败",
                error_code="database_error",
                request_id=request_id
            )
        )
    
    @app.exception_handler(Exception)
    async def handle_general_exception(request: Request, exc: Exception) -> JSONResponse:
        """处理通用异常"""
        request_id = get_request_id(request)
        client_info = get_client_info(request)
        
        # 记录错误日志
        log_error_with_context(
            exc,
            {
                "path": request.url.path,
                "method": request.method,
                "client_ip": client_info["ip"],
                "request_id": request_id,
                "traceback": traceback.format_exc()
            }
        )
        
        return JSONResponse(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            content=format_error_response(
                status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
                message="服务器内部错误",
                error_code="internal_error",
                request_id=request_id
            )
        )


# 导出所有公共类和函数
__all__ = [
    # 错误类
    'APIError',
    'BadRequestError',
    'UnauthorizedError',
    'ForbiddenError',
    'NotFoundError',
    'ConflictError',
    'RateLimitError',
    'ServerError',
    'ServiceUnavailableError',
    
    # 工具函数
    'format_error_response',
    'get_request_id',
    'get_client_info',
    'setup_error_handlers',
]